import { AnimationFrame, Utils, Vector3 } from "babylon-lib/index";
import { Soldier } from "./soldier";
import { Landscape } from "./landscape";
import { SOLDIER_STATE, SoldierManager } from "./soldier-manager";
import { Axis } from "@babylonjs/core/Maths/math.axis";
import { Random } from "babylon-lib/tool/random";
import { UAV } from "./uav";


interface ISoldierActionLogicOptions { }


class SoldierActionLogic {

    private _options: ISoldierActionLogicOptions;
    private _interval = 500;
    private _req = {};
    private _direction = new Vector3();
    private _urgency = 0;
    private _tv0 = new Vector3();
    private _tv1 = new Vector3();
    private _tv2 = new Vector3();

    public readonly name: string;
    public readonly soldier: Soldier;

    constructor(name: string, soldier: Soldier, options: ISoldierActionLogicOptions) {
        this.name = name;
        this.soldier = soldier;
        this._options = options;
    }

    public async active(start: boolean): Promise<void> {
        AnimationFrame.cancel(this._req);
        if (!start) return;
        await Utils.sleep(Random.float(0, 2000));
        this.soldier.walk();
        AnimationFrame.request(() => {
            this._direction.copyFrom(this.soldier.direction);
            this._urgency -= 0.04;
            this._urgency = Math.max(Math.min(this._urgency, 1), 0);
            this.checkSoldiers();
            this.checkLandscape();
            this.checkUAV();
            this.makeDecision();
        }, this._interval, this._interval + 200, this._req);
    }

    private makeDecision(): void {
        if (this._urgency <= 0) {
            this.soldier.turn(Landscape.enemyTargetDirection);
            return;
        }
        this._direction.normalize();
        if (this._urgency > 0) {
            this.soldier.turn(this._direction);
        }
        if (this._urgency <= 0.1) {
            this.soldier.walk();
        }
        if (0.1 < this._urgency && this._urgency <= 0.8) {
            this.soldier.stay();
        }
        if (0.8 < this._urgency) {
            this.soldier.run();
        }
    }

    private checkSoldiers(): void {
        let iDis = 25;
        let aDis = 250000;
        let isd: Soldier | null = null;
        let asd: Soldier | null = null;
        for (const sd of SoldierManager.signedSoldiers) {
            if (sd.id === this.soldier.id) continue;
            const dis = Vector3.DistanceSquared(sd.entity.absolutePosition, this.soldier.entity.absolutePosition);
            if (dis < iDis) {
                isd = sd;
                iDis = dis;
            }
            if (dis > aDis) {
                asd = sd;
                aDis = dis;
            }
        }
        if (isd) {
            const forward = this._tv0.copyFrom(this.soldier.direction);
            const dir = this._tv1.copyFrom(isd.entity.absolutePosition).subtractInPlace(this.soldier.entity.absolutePosition).normalize();
            const crs = Vector3.CrossToRef(Axis.Y, forward, this._tv2);
            crs.y = 0;
            crs.normalize();
            if (Vector3.Dot(crs, dir) > 0) crs.negateInPlace();
            this._direction.addInPlace(crs);
            this._urgency += 0.1;
        }
        if (asd) {
            const dir = this._tv1.copyFrom(asd.entity.absolutePosition).subtractInPlace(this.soldier.entity.absolutePosition);
            dir.y = 0;
            dir.normalize();
            this._direction.addInPlace(dir);
            this._urgency += 0.1;
        }
    }

    private checkUAV(): void {
        const pos = this._tv0.copyFrom(this.soldier.entity.absolutePosition);
        pos.y = 0;
        const tar = this._tv1.copyFrom(UAV.container.absolutePosition);
        tar.y = 0;
        const dis = Vector3.DistanceSquared(pos, tar);
        if (dis < 100) {
            this._urgency += 0.18;
        } else if (dis < 400) {
            this._urgency += 0.06;
        } else if (dis < 2500) {
            this._urgency += 0.02;
        } else {
            return;
        }
    }

    private checkLandscape(): void {
        this.avoidDanger();
        this.outOfBand();
    }

    private avoidDanger(): void {
        const pos = this._tv0.copyFrom(this.soldier.entity.absolutePosition);
        let iDis = 900;
        let ip: Vector3 | null = null;
        for (const dp of Landscape.dangrousPoints) {
            const p = this._tv1.copyFrom(dp[0]);
            const d = Vector3.DistanceSquared(pos, p);
            if (iDis > d) {
                iDis = d;
                ip = p;
            }
        }
        if (!ip) return;
        const dir = ip.subtractInPlace(pos);
        const crs = Vector3.CrossToRef(Axis.Y, dir, this._tv2);
        crs.y = 0;
        crs.normalize();
        if (Vector3.Dot(crs, this.soldier.direction) < 0) crs.negateInPlace();
        this._direction.addInPlace(crs);
        this._urgency += 0.5;
    }

    private outOfBand(): void {
        const pos = this._tv0.copyFrom(this.soldier.entity.absolutePosition);
        pos.y = 0;
        const dis = Vector3.DistanceSquared(pos, Landscape.zoneCenter);
        if (dis < Landscape.zoneExtend * Landscape.zoneExtend) {
            return;
        }

        const dir = new Vector3().copyFrom(pos).subtractInPlace(Landscape.zoneCenter);
        if (Vector3.Dot(dir,Landscape.enemyTargetDirection)>0.9) {
            this.soldier.state = SOLDIER_STATE.SURVIVE;
            this.active(false);
        } else {
            pos.subtractInPlace(Landscape.zoneCenter).negateInPlace();
            pos.y = 0;
            pos.normalize();
            this._direction.addInPlace(pos);
            this._urgency += 0.1;
        }
    }

}


export { SoldierActionLogic };